#include "StdAfx.h"
#include "Defines.h"
#include "Exceptions.h"
#include "ServiceFunctions.h"
#include "Maze.h"

CCrosRoad :: CCrosRoad()  
{
	memset(m_possible_cells, 0, sizeof(m_possible_cells));
	m_num_valid_cells = 0;
	
	m_last_used_cell  = -1;
}

CCrosRoad :: ~CCrosRoad() 
{
}

CellPosition* CCrosRoad :: AddCell(int col, int row, int origin_col, int origin_row)
{
	if(m_num_valid_cells < 4)
	{
		m_possible_cells[m_num_valid_cells].col = col;
		m_possible_cells[m_num_valid_cells].row = row;

		m_possible_cells[m_num_valid_cells].origin_col = origin_col;
		m_possible_cells[m_num_valid_cells].origin_row = origin_row;

		m_possible_cells[m_num_valid_cells].already_used = false;

		m_num_valid_cells++;

		return &m_possible_cells[m_num_valid_cells];
	}

	return NULL;
}

CellPosition* CCrosRoad :: FindCell(int col, int row)
{
	for(int i = 0; i < m_num_valid_cells; i++)
	{
		if(m_possible_cells[i].col == col && m_possible_cells[i].row == row)
			return &m_possible_cells[i];
	}

	return NULL;
}

CellPosition* CCrosRoad :: GetFirstNotUsedCell()
{
	for(int i = 0; i < m_num_valid_cells; i++)
	{
		if(!m_possible_cells[i].already_used)
		{
			m_last_used_cell = i;
			return &m_possible_cells[i];
		}
	}

	m_last_used_cell = -1;

	return NULL;
}

CMaze :: CMaze(int num_rows, int num_columns)
{
	//form the maze
	m_num_rows    = num_rows;
	m_num_columns = num_columns;

	m_created     = false;
	m_route_found = false;

	if(m_num_rows < 4 || m_num_columns < 4)
	{
		m_valid = false;

		throw CMazeBadParamsException("The size of maze should be at least 4x4");
	}

	bool memory_fault = false;

	m_valid = true;

	memset(m_cells, NULL, sizeof(m_cells));

	for(int i = 0; i < MAZE_Y_SIZE; i++)
	{
		for(int j = 0; j < MAZE_X_SIZE; j++)
		{
			m_cells[i][j] = new CMazeCell();
			if(!m_cells[i][j])
			{
				memory_fault = true;
				break;
			}

			//form maze's boundaries
			if(i == 0 || i == MAZE_Y_SIZE - 1)
			{
				if(j != 0 && j != MAZE_X_SIZE - 1)
					m_cells[i][j]->SetTopWall(true);	
				
				m_cells[i][j]->Ban(true);
			}

			if(j == 1 || j == MAZE_X_SIZE - 1)
			{
				if(i != 0 && i != MAZE_Y_SIZE - 1)
					m_cells[i][j]->SetLeftWall(true);
			}

			if(j == 0 || j == MAZE_X_SIZE - 1)
			{
				m_cells[i][j]->Ban(true);
			}

			//for all other cells
			if(i > 0 && i != MAZE_Y_SIZE - 1 &&
			   j > 0 && j != MAZE_X_SIZE - 1)
			{
				m_cells[i][j]->SetLeftWall(true);
				m_cells[i][j]->SetTopWall(true);
			}

			m_cells[i][j]->SetRow(i);
			m_cells[i][j]->SetCol(j);
		}
	
		if(memory_fault)
		{
			break;
		}
	}

	//faulty case
	if(memory_fault)
	{
		m_valid = false;	
		throw CMazeException("Memory allocation error");
	}

	//additional stuff for drawing
	m_x_cell_size = (float)X_RES / (float)m_num_columns;
	m_y_cell_size = (float)Y_RES / (float)m_num_rows;

	//init random generator
	srand((unsigned)time(NULL));

	//clean stacks
	CleanCellsStack();
	CleanCrosStack();

	//m_cells_stack.reserve(MAZE_X_SIZE*MAZE_Y_SIZE);
	//m_cros_stack.reserve(MAZE_X_SIZE*MAZE_Y_SIZE);

	m_start_cell_x  = 0;
	m_start_cell_y  = 0;

	m_finish_cell_x = 0;
	m_finish_cell_y = 0;

}

CMaze :: ~CMaze()
{
	for(int i = 0; i < MAZE_Y_SIZE; i++)
	{
		for(int j = 0; j < MAZE_X_SIZE; j++)
		{
			if(m_cells[i][j])
			{
				delete m_cells[i][j];
				m_cells[i][j] = NULL;				
			}
		}
	}
	
	CleanCellsStack();
	CleanCrosStack();

	m_valid = false;
}

void CMaze :: CleanCellsStack()
{
	if(m_cells_stack.size() == 0)
	{
		return;
	}
	
	CellPosContainerI cells_i;

	for(cells_i = m_cells_stack.begin(); cells_i != m_cells_stack.end(); cells_i++);
	{
		CellPosition *cur_pos = *cells_i;

		if(cur_pos)
			delete cur_pos;
	}

	m_cells_stack.clear();
}

void CMaze :: CleanCrosStack()
{
	if(m_cros_stack.size() == 0)
	{
		return;
	}
	
	CrosRoadContainerI cros_i;

	for(cros_i = m_cros_stack.begin(); cros_i != m_cros_stack.end(); cros_i++);
	{
		CCrosRoad *cur_cros = *cros_i;

		if(cur_cros)
			delete cur_cros;
	}

	m_cros_stack.clear();
}

void CMaze :: Draw()
{
	for(int i = 0; i < MAZE_Y_SIZE; i++)
	{
		for(int j = 0; j < MAZE_X_SIZE; j++)
		{
			m_cells[i][j]->Draw(m_x_cell_size, m_y_cell_size);
		}
	}
}

//get random value from [0 .. max-1]
int CMaze :: Random(int max)
{
	//init random generator
	//long ltime;
	//time(&ltime);
	//srand(ltime/10);

	//float temp = (float)rand() / (float)RAND_MAX;

	//return (int)(((float)max - 1.0) * temp);

	return rand()%max;
}

void CMaze :: AddCellToStack(CellPosition *cell_pos)
{
	CellPosContainerI cell_i;
	bool already_in_stack = false;

	for(cell_i = m_cells_stack.begin(); cell_i != m_cells_stack.end(); cell_i++)
	{
		CellPosition *cur_cell = (CellPosition*)*cell_i;

		if(cur_cell->row == cell_pos->row && cur_cell->col == cell_pos->col)
		{
			already_in_stack = true;
			break;
		}
	}

	if(!already_in_stack)
	{
		m_cells_stack.push_back(cell_pos);
	}
}

void CMaze :: RemoveCellFromStack(int row, int col)
{
	CellPosContainerI cell_i;

	for(cell_i = m_cells_stack.begin(); cell_i != m_cells_stack.end(); cell_i++)
	{
		CellPosition *cur_cell = (CellPosition*)*cell_i;

		if(cur_cell->row == row && cur_cell->col == col)
		{
			m_cells_stack.erase(cell_i);
			break;
		}
	}
}

void CMaze :: RemoveCrosRoadFromStack(int row, int col)
{
	CrosRoadContainerI cros_i;

	for(cros_i = m_cros_stack.begin(); cros_i != m_cros_stack.end(); cros_i++)
	{
		CCrosRoad *cur_cros = (CCrosRoad*)*cros_i;

		if(cur_cros->GetRow() == row && cur_cros->GetCol() == col)
		{
			m_cros_stack.erase(cros_i);
			break;
		}
	}
}

void CMaze :: AddCrosRoadToStack(CCrosRoad *cros)
{
	CrosRoadContainerI cros_i;
	bool already_in_stack = false;

	for(cros_i = m_cros_stack.begin(); cros_i != m_cros_stack.end(); cros_i++)
	{
		CCrosRoad *cur_cros = (CCrosRoad*)*cros_i;

		if(cur_cros->GetRow() == cros->GetRow() && cur_cros->GetCol() == cros->GetCol())
		{
			already_in_stack = true;
			break;
		}
	}

	if(!already_in_stack)
	{
		m_cros_stack.push_back(cros);
	}
}

Direction CMaze :: GetDirection(int cur_x, int cur_y, int prev_x, int prev_y)
{
	Direction direction;

	if(cur_x > prev_x)
		direction = right;

	if(cur_x < prev_x)
		direction = left;

	if(cur_y > prev_y)
		direction = up;

	if(cur_y < prev_y)
		direction = down;

	return direction;
}

LineType CMaze :: GetLineType(Direction d1, Direction d2)
{
	LineType result;
	
	switch(d1)
	{
		case left :
		{
			switch(d2)
			{
				case left  : result = lHor;  break;
				case up    : result = l3_12; break;
				case down  : result = l3_6;  break;
			}
			break;
		}
		case right :
		{
			switch(d2)
			{
				case right : result = lHor;  break;
				case up    : result = l9_12; break;
				case down  : result = l6_9;  break;
			}
			break;
		}
		case up :
		{
			switch(d2)
			{
			    case up    : result = lVert; break;
				case right : result = l3_6; break;
				case left  : result = l6_9;  break;
			}
			break;
		}
		case down :
		{
			switch(d2)
			{
				case left  : result = l9_12; break;
				case right : result = l3_12; break;
				case down  : result = lVert; break;
			}
			break;
		}
	}

	return result;
}

void CMaze :: EatAppropriateWall(int cur_x, int cur_y, int dest_x, int dest_y)
{
	Direction direction;

	if(dest_x > cur_x)
		direction = right;

	if(dest_x < cur_x)
		direction = left;

	if(dest_y > cur_y)
		direction = up;

	if(dest_y < cur_y)
		direction = down;
			
	int eated_row, eated_col;
	switch(direction)
	{
		case right : 
		{
			m_cells[cur_y][cur_x + 1]->SetLeftWall(false);
			eated_row = cur_y;
			eated_col = cur_x + 1;
			break;
		}
		case left  : 
		{
			m_cells[cur_y][cur_x]->SetLeftWall(false);
			eated_row = cur_y;
			eated_col = cur_x;
			break;
		}
		case up    : 
		{
			m_cells[cur_y][cur_x]->SetTopWall(false);
			eated_row = cur_y;
			eated_col = cur_x;
			break;
		}
		case down  : 
		{
			m_cells[cur_y - 1][cur_x]->SetTopWall(false);
			eated_row = cur_y - 1;
			eated_col = cur_x;
			break;
		}
	}//switch(orientation)

	//glClear(GL_COLOR_BUFFER_BIT);

	m_cells[eated_row][eated_col]->Draw(m_x_cell_size, m_y_cell_size);

#if USE_DELAY_FOR_CREATION	
	Sleep(CREATION_DELAY);
#endif

	RemoveCellFromStack(cur_y, cur_x);
	RemoveCellFromStack(eated_row, eated_col);
}

bool CMaze :: CellIsClosed(int x, int y)
{
	if(m_cells[y][x]    ->HasTopWall() && m_cells[y][x]    ->HasLeftWall() &&
	   m_cells[y - 1][x]->HasTopWall() && m_cells[y][x + 1]->HasLeftWall())
	{
		return true;
	}
	else
	{
		return false;
	}
}

void CMaze :: FormMaze()
{
	clock_t start, finish;

	CleanCellsStack();
	CleanCrosStack();

	m_created     = false;
	m_route_found = false;

	char buffer[512];

	int cur_mouse_pos_x, cur_mouse_pos_y;
	
	//put the "mouse" in some non-banned random cell
	while(1)
	{
		cur_mouse_pos_x = Random(m_num_columns);
		cur_mouse_pos_y = Random(m_num_rows);

		if(!m_cells[cur_mouse_pos_y][cur_mouse_pos_x]->Banned())
			break;
	}

	start = clock();

	//start the "mouse"
	while(1)
	{
		CellPosition neighbours[4];
		memset(neighbours, 0, sizeof(neighbours));

		if(DRAW_MARKER_ON_MAZE_CREATION)
		{
			m_cells[cur_mouse_pos_y][cur_mouse_pos_x]->DrawMarker(m_x_cell_size, m_y_cell_size);
		}

		//if we are on the cell, it is not closed. so, if it was added before, remove it.
		RemoveCellFromStack(cur_mouse_pos_y, cur_mouse_pos_x);

		//wsprintf(buffer, "Start of loop, \nCurrent position - Row %d, Col %d", cur_mouse_pos_y, cur_mouse_pos_x);
		//MessageBox(NULL, buffer, "Debug", MB_OK);


		//get all closed cells near current one, except banned cells
		int num_closed_cells = AnalizeNeighbours(cur_mouse_pos_x, 
			                                     cur_mouse_pos_y, 
												 neighbours);

		//all cells are not closed, get one from stack
		if(num_closed_cells == 0)
		{
			//no cells in the stack, job is done !
			if(m_cells_stack.size() == 0)
			{
				break;
			}
		
			CellPosContainerI i;

			i = m_cells_stack.end();
			i--;
			
			CellPosition *cur_position = *i;
			m_cells_stack.pop_back();

			//wsprintf(buffer, "No close cells, \ngot from stack  - Row %d, Col %d", cur_position->row, cur_position->col);
			//MessageBox(NULL, buffer, "Debug", MB_OK);


			EatAppropriateWall(cur_position->origin_col, cur_position->origin_row, 
				               cur_position->col, cur_position->row);
		
			cur_mouse_pos_x = cur_position->col;
			cur_mouse_pos_y = cur_position->row;

			continue;
		}

		//the only cell found
		if(num_closed_cells == 1)
		{
			int found_pos_x = neighbours[0].col;
			int found_pos_y = neighbours[0].row;

			EatAppropriateWall(cur_mouse_pos_x, cur_mouse_pos_y, 
				               found_pos_x,     found_pos_y);
		
			cur_mouse_pos_x = found_pos_x;
			cur_mouse_pos_y = found_pos_y;

			continue;
		}//if(num_closed_cells == 1), the only cell has been found
		else//more then one cell has been found
		{
			int cell_to_choose = Random(num_closed_cells);
		
			//Put other cells to the stack first
			for(int i = 0; i < num_closed_cells; i++)
			{
				if(i != cell_to_choose)
				{
					CellPosition *cell_pos = new CellPosition;
					cell_pos->col = neighbours[i].col;
					cell_pos->row = neighbours[i].row;

					cell_pos->origin_col = cur_mouse_pos_x;
					cell_pos->origin_row = cur_mouse_pos_y;

					AddCellToStack(cell_pos);
					//m_cells_stack.push_back(cell_pos);
				}
			}

			//work with one of found cells
			int found_pos_x = neighbours[cell_to_choose].col;
			int found_pos_y = neighbours[cell_to_choose].row;

			EatAppropriateWall(cur_mouse_pos_x, cur_mouse_pos_y, 
				               found_pos_x,     found_pos_y);
		
			cur_mouse_pos_x = found_pos_x;
			cur_mouse_pos_y = found_pos_y;
		}//more then one cell has been found
	}//while(1)

	//mark start and finish of the maze
	m_cells[MAZE_Y_SIZE - 2][1]->SetLeftWall(false);
	m_cells[1][MAZE_X_SIZE - 1]->SetLeftWall(false);

	m_cells[MAZE_Y_SIZE - 2][1]->Draw(m_x_cell_size, m_y_cell_size);
	m_cells[1][MAZE_X_SIZE - 1]->Draw(m_x_cell_size, m_y_cell_size);

	glFlush();

	m_created = true;

	m_start_cell_x  = 1;
	m_start_cell_y  = MAZE_Y_SIZE - 2;

	m_finish_cell_x = MAZE_X_SIZE - 2;
	m_finish_cell_y = 1;

    finish   = clock();
    double duration = (double)(finish - start) / CLOCKS_PER_SEC;

	sprintf(buffer, "Time %f", (float)duration);
	MessageBox(NULL, buffer, "Time", MB_OK);
}								   

int CMaze :: GetCellsToGoTo(int cur_x, int cur_y, int prev_x, int prev_y, CellPosition *cells_to_go)
{
	int num_ret = 0;
	//analize four neighbours

	//bottom
	if(!m_cells[cur_y - 1][cur_x]->Banned())
	{
		if(cur_y - 1 != prev_y)
		{
			if(!m_cells[cur_y - 1][cur_x]->HasTopWall())
			{
				cells_to_go[num_ret].col = cur_x;
				cells_to_go[num_ret].row = cur_y - 1;

				num_ret++;
			}
		}
	}
	
	//top
	if(!m_cells[cur_y + 1][cur_x]->Banned())
	{
		if(cur_y + 1 != prev_y)
		{
			if(!m_cells[cur_y][cur_x]->HasTopWall())
			{
				cells_to_go[num_ret].col = cur_x;
				cells_to_go[num_ret].row = cur_y + 1;

				num_ret++;
			}
		}
	}

	//left
	if(!m_cells[cur_y][cur_x - 1]->Banned())
	{
		if(cur_x - 1 != prev_x)
		{
			if(!m_cells[cur_y][cur_x]->HasLeftWall())
			{
				cells_to_go[num_ret].col = cur_x - 1;
				cells_to_go[num_ret].row = cur_y;

				num_ret++;
			}
		}
	}

	//right
	if(!m_cells[cur_y][cur_x + 1]->Banned())
	{
		if(cur_x + 1 != prev_x)
		{
			if(!m_cells[cur_y][cur_x + 1]->HasLeftWall())
			{
				cells_to_go[num_ret].col = cur_x + 1;
				cells_to_go[num_ret].row = cur_y;

				num_ret++;
			}
		}
	}

	return num_ret;
}

int CMaze :: AnalizeNeighbours(int cur_x, int cur_y, CellPosition *neighbours)
{
	int num_ret = 0;
	//analize four neighbours

	//bottom
	if( ! m_cells[cur_y - 1][cur_x]->Banned())
	{
		if(CellIsClosed(cur_x, cur_y - 1))
		{
			neighbours[num_ret].col = cur_x;
			neighbours[num_ret].row = cur_y - 1;

			num_ret++;
		}
	}
	
	//top
	if( ! m_cells[cur_y + 1][cur_x]->Banned())
	{
		if(CellIsClosed(cur_x, cur_y + 1))
		{
			neighbours[num_ret].col = cur_x;
			neighbours[num_ret].row = cur_y + 1;

			num_ret++;
		}
	}

	//left
	if( ! m_cells[cur_y][cur_x - 1]->Banned())
	{
		if(CellIsClosed(cur_x - 1, cur_y))
		{
			neighbours[num_ret].col = cur_x - 1;
			neighbours[num_ret].row = cur_y;

			num_ret++;
		}
	}

	//right
	if( ! m_cells[cur_y][cur_x + 1]->Banned())
	{
		if(CellIsClosed(cur_x + 1, cur_y))
		{
			neighbours[num_ret].col = cur_x + 1;
			neighbours[num_ret].row = cur_y;

			num_ret++;
		}
	}

	return num_ret;
}

bool CMaze::TraceRoute()
{
	if(!m_created)
	{
		MessageBox(NULL, "Maze is not created !", "Error", MB_OK);
	
		return false;
	}

	CleanCellsStack();
	CleanCrosStack();

	int cur_mouse_pos_x,  cur_mouse_pos_y;
	int prev_mouse_pos_x, prev_mouse_pos_y;

	cur_mouse_pos_x = m_start_cell_x;
	cur_mouse_pos_y = m_start_cell_y;

	prev_mouse_pos_x = cur_mouse_pos_x;
	prev_mouse_pos_y = cur_mouse_pos_y;

	bool       route_found        = false;
	bool       work_with_crosroad = false;
	CCrosRoad *currentCrosRoad = NULL;
	while(1)
	{
		if(DRAW_MARKER_ON_ROUTING)
		{
			//mark current position
			m_cells[cur_mouse_pos_y][cur_mouse_pos_x]->DrawMarker(m_x_cell_size, m_y_cell_size);
			//m_cells[prev_mouse_pos_y][prev_mouse_pos_x]->DrawMarker(m_x_cell_size, m_y_cell_size, true);
		}

		//we've got the route - stop this loop
		if(cur_mouse_pos_x == m_finish_cell_x && cur_mouse_pos_y == m_finish_cell_y)
		{
			route_found = true;
			break;
		}

		int num_cells_to_go ;
		CellPosition cells_to_go[4];
		memset(cells_to_go, 0, sizeof(cells_to_go));
		
		//get cells available to go to
		num_cells_to_go = GetCellsToGoTo(cur_mouse_pos_x, cur_mouse_pos_y, 
			                             prev_mouse_pos_x, prev_mouse_pos_y, 
										 cells_to_go);

		//return to last crossroad
		if(num_cells_to_go == 0)
		{
			if(m_cros_stack.size() == 0)
			{
				route_found = false;
				break;
			}
		
			CrosRoadContainerI i;
			
			CellPosition *cur_position = NULL;
			bool stop_working = false;
			while(1)
			{
				if(m_cros_stack.size() == 0)
				{
					stop_working = true;
					route_found  = false;
					break;
				}

				i = m_cros_stack.end();
				i--;

				currentCrosRoad = *i;
				cur_position = currentCrosRoad->GetFirstNotUsedCell();

				if(!cur_position)
					m_cros_stack.pop_back();
				else
					break;
			}

			//no more crosroads, no more cells to go, route not found
			if(stop_working)
			{
				break;
			}

			cur_position->already_used = true;

			cur_mouse_pos_x = cur_position->col;
			cur_mouse_pos_y = cur_position->row;

			prev_mouse_pos_x = cur_position->origin_col;
			prev_mouse_pos_y = cur_position->origin_row;
		}

		//the only way - use it
		if(num_cells_to_go == 1)
		{
			prev_mouse_pos_x = cur_mouse_pos_x;
			prev_mouse_pos_y = cur_mouse_pos_y;
			
			cur_mouse_pos_x = cells_to_go[0].col;
			cur_mouse_pos_y = cells_to_go[0].row;
		}
		
		//multiple roads available, use on of them, push others to stack
		if(num_cells_to_go > 1)
		{

			CCrosRoad *cros_road = new CCrosRoad();
					
			cros_road->SetRow(cur_mouse_pos_y);
			cros_road->SetCol(cur_mouse_pos_x);

			for(int i = 0; i < num_cells_to_go; i++)
			{
				cros_road->AddCell(cells_to_go[i].col, cells_to_go[i].row,
					                cur_mouse_pos_x,    cur_mouse_pos_y);
					         
			}			

			CellPosition *cur_cell = cros_road->GetFirstNotUsedCell();

			cur_cell->already_used = true;

			AddCrosRoadToStack(cros_road);
			
			prev_mouse_pos_x = cur_mouse_pos_x;
			prev_mouse_pos_y = cur_mouse_pos_y;
			
			cur_mouse_pos_x = cur_cell->col;
			cur_mouse_pos_y = cur_cell->row;

		}//if(num_cells_to_go > 1)

#if USE_DELAY_FOR_ROUTING
		Sleep(TRACE_DELAY);
#endif
	}

	m_route_found = route_found;

	return route_found;
}

void CMaze :: DrawRoute()
{
	if(!m_created || !m_route_found)
	{
		return;
	}

	int cur_mouse_pos_x,  cur_mouse_pos_y;
	int prev_mouse_pos_x, prev_mouse_pos_y;

	cur_mouse_pos_x = m_start_cell_x;
	cur_mouse_pos_y = m_start_cell_y;

	prev_mouse_pos_x = cur_mouse_pos_x - 1;
	prev_mouse_pos_y = cur_mouse_pos_y;

	CCrosRoad *currentCrosRoad = NULL;
	CrosRoadContainerI cros_i;

	cros_i = m_cros_stack.begin();

	Direction cur_direction  = right;
	Direction next_direction;

	while(1)
	{
		currentCrosRoad = *cros_i;
		
		//we've got the route - stop this loop
		if(cur_mouse_pos_x == m_finish_cell_x && cur_mouse_pos_y == m_finish_cell_y)
		{
			break;
		}

		if(DRAW_LINE_INSTEAD_OF_MARKER)
		{
			if(cur_mouse_pos_x != prev_mouse_pos_x ||
			   cur_mouse_pos_y != prev_mouse_pos_y)
			{
				int t_num_cells_to_go ;
				CellPosition t_cells_to_go[4];
				memset(t_cells_to_go, 0, sizeof(t_cells_to_go));
				
				//get cells available to go to
				t_num_cells_to_go = GetCellsToGoTo(cur_mouse_pos_x, cur_mouse_pos_y, 
					                               prev_mouse_pos_x, prev_mouse_pos_y, 
					                               t_cells_to_go);
				
				//the only possible way - use it
				if(t_num_cells_to_go == 1)
				{
					next_direction = GetDirection(t_cells_to_go[0].col, 
						                          t_cells_to_go[0].row,
						                          cur_mouse_pos_x, 
												  cur_mouse_pos_y);
				}
				
				//crosroad - get the direction from stack
				if(t_num_cells_to_go > 1)
				{
					CellPosition *t_cur_cell = currentCrosRoad->GetLastUsedCell();
					
					if(t_cur_cell)
					{
						next_direction = GetDirection(t_cur_cell->col, 
							                          t_cur_cell->row,
							                          cur_mouse_pos_x, 
													  cur_mouse_pos_y);
					}
				}
				
				LineType l_type = GetLineType(cur_direction, next_direction);

				int pos_x, pos_y;

				pos_x = cur_mouse_pos_x;
				pos_y = cur_mouse_pos_y;

				switch(l_type)
				{
					case lHor  : 
					{
						m_cells[pos_y][pos_x]->DrawHorLine(m_x_cell_size, m_y_cell_size);
						break;
					}
					case lVert : 
					{
						m_cells[pos_y][pos_x]->DrawVertLine(m_x_cell_size, m_y_cell_size);
						break;
					}
					case l9_12 : 
					{
						m_cells[pos_y][pos_x]->Draw9_12Line(m_x_cell_size, m_y_cell_size);
						break;
					}
					case l3_12 : 
					{
						m_cells[pos_y][pos_x]->Draw3_12Line(m_x_cell_size, m_y_cell_size);
						break;
					}
					case l3_6  : 
					{
						m_cells[pos_y][pos_x]->Draw3_6Line(m_x_cell_size, m_y_cell_size);
						break;
					}
					case l6_9  : 
					{
						m_cells[pos_y][pos_x]->Draw6_9Line(m_x_cell_size, m_y_cell_size);
						break;
					}
				}
			}
		}//if(DRAW_LINE_INSTEAD_OF_MARKER)
		else
		{
			//mark current position
			m_cells[cur_mouse_pos_y][cur_mouse_pos_x]->DrawRouteMarker(m_x_cell_size, m_y_cell_size);
			//m_cells[prev_mouse_pos_y][prev_mouse_pos_x]->DrawMarker(m_x_cell_size, m_y_cell_size, true);
		}

		currentCrosRoad = *cros_i;

		int num_cells_to_go ;
		CellPosition cells_to_go[4];
		memset(cells_to_go, 0, sizeof(cells_to_go));
		
		//get cells available to go to
		num_cells_to_go = GetCellsToGoTo(cur_mouse_pos_x, cur_mouse_pos_y, 
			                             prev_mouse_pos_x, prev_mouse_pos_y, 
										 cells_to_go);

		//the only possible way - use it
		if(num_cells_to_go == 1)
		{
			prev_mouse_pos_x = cur_mouse_pos_x;
			prev_mouse_pos_y = cur_mouse_pos_y;
			
			cur_mouse_pos_x = cells_to_go[0].col;
			cur_mouse_pos_y = cells_to_go[0].row;
		}

		//crosroad - get the direction from stack
		if(num_cells_to_go > 1)
		{
			CellPosition *cur_cell = currentCrosRoad->GetLastUsedCell();
			if(!cur_cell)
				break;

			prev_mouse_pos_x = cur_mouse_pos_x;
			prev_mouse_pos_y = cur_mouse_pos_y;

			cur_mouse_pos_x = cur_cell->col;
			cur_mouse_pos_y = cur_cell->row;

			cros_i++;
		}

		cur_direction = GetDirection(cur_mouse_pos_x,  cur_mouse_pos_y,
			                         prev_mouse_pos_x, prev_mouse_pos_y);
	}	
}

void CMaze :: SaveMazeToFile(char *fname)
{
	if(!m_created)
	{
		return;
	}

	FILE *fp = fopen(fname, "wt");

	fprintf(fp, "%d\n", MAZE_Y_SIZE);
	fprintf(fp, "%d\n", MAZE_X_SIZE);

	for(int i = 0; i < MAZE_Y_SIZE - 1; i++)
	{
		for(int j = 0; j < MAZE_X_SIZE; j++)
		{
			int num_walls;//0 - no, 1 - left, 2 - top, 3 - both

			bool left = m_cells[i][j]->HasLeftWall();
			bool top  = m_cells[i][j]->HasTopWall();

			if(left && top)
			{
				num_walls = 3;
			}
			else if(left)
			{
				num_walls = 1;
			}
			else if(top)
			{
				num_walls = 2;
			}
			else
			{
				num_walls = 0;
			}

			fprintf(fp, "%d", num_walls);
		}

		fprintf(fp, "\n");
	}

	fclose(fp);
}
